<script setup lang="ts">
import { type Component, computed, h, inject, provide, type Ref, shallowRef, type VNode, watch } from "vue";
import type { ComponentType } from "@/framework/vue/types";
import type { ToggleItemCustomHooks } from "@/components/framework/toggle-view-helper";

const { cacheEnabled = true, ...props } = defineProps<{
  // 组件ID
  itemId: string;
  // 组件
  component: ComponentType;
  // 是否启用缓存
  cacheEnabled?: boolean;
}>();

const activeKey = inject<Ref<string>>("toggle-view:active-key");
const visible = computed(() => activeKey?.value == props.itemId);
const content = shallowRef<VNode>();
const contentRef = shallowRef<any>();

const getContentVNode = async () => {
  if (typeof props.component === "function") {
    try {
      const resp = await (props.component as () => Promise<{ default: ComponentType }>)();
      return resp?.default != undefined ? h(resp.default) : undefined;
    } catch (e: any) {
      console.error(e);
      return h("span", { style: { color: "red" } }, `Component error: ${e}`);
    }
  }
  return h(props.component as Component);
};

const hooks = {
  onShow: [] as Function[],
  onHide: [] as Function[],
};

provide("toggle-item-id", props.itemId);
provide("toggle-item-custom-hooks", <ToggleItemCustomHooks>{
  onShow: (fn: Function) => hooks.onShow.push(fn),
  onShowOnce: (fn: Function) => {
    const _fn = () => {
      fn();
      hooks.onShow.splice(hooks.onShow.indexOf(_fn), 1);
    };
    hooks.onShow.push(_fn);
  },
  removeShowHandler: (fn: Function) => hooks.onShow.splice(hooks.onShow.indexOf(fn), 1),
  onHide: (fn: Function) => hooks.onHide.push(fn),
  onHideOnce: (fn: Function) => {
    const _fn = () => {
      fn();
      hooks.onHide.splice(hooks.onHide.indexOf(_fn), 1);
    };
    hooks.onHide.push(_fn);
  },
  removeHideHandler: (fn: Function) => hooks.onHide.splice(hooks.onHide.indexOf(fn), 1),
});

watch(
  visible,
  async value => {
    if (value) {
      // 显示
      if (content.value == undefined) {
        content.value = await getContentVNode();
      } else {
        hooks.onShow.forEach(fn => fn());
      }
    } else {
      // 隐藏
      if (!cacheEnabled) {
        content.value = undefined;
      } else {
        hooks.onHide.forEach(fn => fn());
      }
    }
  },
  { immediate: true },
);
</script>

<template>
  <template v-if="cacheEnabled">
    <component v-show="visible && content" :is="content" ref="contentRef" />
  </template>
  <template v-else>
    <component v-if="visible && content" :is="content" />
  </template>
</template>
